<?php

// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Admin setttings objects for component 'theme_rlmaster'
 *
 * @package   theme-rlmaster
 * @author    Tyler Bannister <tyler.bannister@remote-learne.net>
 * @copyright 2011 Remote Learner  http://www.remote-learner.net/
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

/**
 * We want to allow multiple copies of this theme to be used on a site,
 * therefore we're implenting an "already loaded" detection system to
 * prevent redeclaration of the classes used in the theme.
 */
if (!class_exists('rlmaster_admin_setting_controls')) {
    global $CFG;

    include_once($CFG->libdir.'/adminlib.php');
    include_once($CFG->dirroot .'/repository/lib.php');
    require_once(dirname(__FILE__).'/lib.php');

    /**
     * This is a callback function to refresh the theme cache when the admin setting is changed
     */
    function rlmaster_admin_onsave_refresh() {
        global $CFG;

        // Force clear the cache
        rlmaster_reset_theme_cache($CFG->theme);

        // Get current tab
        $tab = required_param('s_theme_rlmaster_tabs_new', PARAM_INT);
        $return = $CFG->wwwroot.'/admin/settings.php?section=themesettingrlmaster&s_theme_rlmaster_tabs='.$tab;
        redirect($return);
    }

    /**
     * This object organizes color settings into a single element to make setting colors easier
     *
     * Notes:
     * 1) Automatically creates a sample_<key> css rule for each section's preview cell
     * 2) Changing any color value should change the preview cell
     * 3) The configuration array looks like this:
     *   'section1' => array ('name' => $name,
     *                        'fore' => $color,
     *                        'back' => $color)
     *
     * @author  Tyler Bannister <tyler.bannister@remote-learne.net>
     * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
     */
    class rlmaster_admin_setting_colorarray extends admin_setting {
        public static $sections = array(
                'colorsbasic' => array(
                    'main_fore',
                    'main_back',
                    'title_fore',
                    'titleshadow_fore',
                    'link_fore',
                    'link_back',
                    'linkhover_fore',
                    'linkhover_back',
                    'generalbox_fore',
                    'generalbox_back'
                ),
                'colorsblock' => array(
                    'blockheader_fore',
                    'titleshadow_back',
                    'blockheader_back',
                    'blockborder_fore',
                    'block_fore',
                    'block_back',
                    'blockborder_back'
                ),
                'colorscalendar' => array(
                    'cal_course_fore',
                    'cal_course_back',
                    'cal_global_fore',
                    'cal_global_back',
                    'cal_group_fore',
                    'cal_group_back',
                    'cal_user_fore',
                    'cal_user_back'
                ),
                'colorscustommenu' => array(
                    'custommenu_fore',
                    'custommenu_back',
                    'custommenuborder_fore',
                    'custommenuhover_fore',
                    'custommenuhover_back'
                ),
                'colordock' => array(
                    'dock_fore',
                    'dock_back',
                    'dockactive_fore',
                    'dockactive_back'
                ),
                'colorsfooter' => array(
                    'footer_fore',
                    'footer_back',
                    'footerlink_fore',
                    'footerlink_back'
                ),
                'colorsforum' => array(
                    'forum_fore',
                    'forum_back',
                    'forumstarter_fore',
                    'forumstarter_back',
                    'title_back',
                    'heading_fore',
                    'heading_back'
                ),
                'colorsheader' => array(
                    'header_fore',
                    'header_back',
                    'headerlink_fore',
                    'headerlink_back'
                ),
                'colorsnavbar' => array(
                    'navbar_fore',
                    'navbar_back',
                    'navbarlink_fore',
                    'navbarlink_back'
                ),
                'colorscoursesection' => array(
                    'section_back',
                    'sectioncontent_fore',
                    'sectioncontent_back',
                    'current_back'
                )
        );

        public static $properties = array('fore', 'back');

        protected $colors = array();

        protected $component;
        protected $theme;

        protected $filename;

        protected $autosave = false;

        /**
         * Config color array constructor
         *
         * @param string $name        Unique ascii name, either 'mysetting' for settings that in
         *                            config, or 'myplugin/mysetting' for ones in config_plugins.
         * @param string $visiblename Localised
         * @param string $description Long localised info
         * @param string $autosave    Whether to automatically save
         * @uses $CFG;
         */
        public function __construct($name, $visiblename, $description, $autosave = false) {
            global $CFG, $PAGE;

            parent::__construct($name, $visiblename, $description, '');

            $this->component = $this->plugin;
            $this->filename  = $CFG->dataroot .'/repository/'. $this->component .'/colors.csv';
            $this->autosave  = $autosave;
            $this->theme     = substr($this->component, 6);

            $this->initialize_colors();

            // This must be done before the header is printed.  Output_html occurs after.
            if (!$PAGE->requires->is_head_done()) {
                error_log('printing requires for colorpicker.js');
                $PAGE->requires->css('/theme/'. $this->theme .'/style/colorpicker.css');
                $PAGE->requires->js('/theme/'. $this->theme .'/javascript/colorpicker.js');
            }
        }

        /**
         * Initialize the colors array
         */
        protected function initialize_colors() {
            $prefix = 'THEME_RLMASTER_DEFAULT_COLOR_';

            foreach (self::$sections as $k => $v) {
                foreach ($v as $value) {
                    $name = $value;
                    $constant = $prefix.strtoupper($name);
                    $setting  = $this->config_read($name);

                    if ($setting !== null) {
                        $this->colors[$name] = $setting;
                    } else if (defined($constant)) {
                        $this->colors[$name] = constant($constant);
                    } else {
                        $this->colors[$name] = '#000000';
                    }
                }
            }
        }

        /**
         * Get the default settings
         *
         * @return array An associative array of setting => color
         */
        public function get_defaultsetting() {
            $prefix   = 'THEME_RLMASTER_DEFAULT_COLOR_';
            $defaults = array();

            foreach ($this->colors as $name => $value) {
                $constant = $prefix . strtoupper($name);

                if (defined($constant)) {
                    $defaults[$name] = constant($constant);
                } else {
                    $defaults[$name] = '#000000';
                }
            }
            return $defaults;
        }

        /**
         * Generate the css to color the preview cells on load.
         *
         * @return string The css block for the preview cells.
         */
        public function generate_sample_css() {
            $css = array();
            $css[] = '<style type="text/css">';
            $css[] = '/* Sample Block CSS for Color Picker */';

            foreach (self::$sections as $section) {
                $css[] = '.sample_'. $section .' {';
                $css[] = '  color: '. $this->colors[$section .'_fore'] .';';
                $css[] = '  background-color: '. $this->colors[$section .'_back'] .';';
                $css[] = '}';
            }

            $css[] = '</style>';

            return implode("\n", $css);
        }

        /**
         * Returns an HTML string
         *
         * @param mixed  $data  Array or string depending on setting
         * @param string $query Query
         * @return string Returns an HTML string
         * @uses $CFG;
         * @uses $PAGE;
         */
        public function output_html($data, $query='') {
            global $CFG, $PAGE;
            $html = array();

            $html[] = '<div class="form-item clearfix" id="admin-'.$this->name.'">';
            $html[] = '<div id="'. $this->get_id() .'" class="form-setting">';

            $this->theme     = substr($this->component, 6);
            $colorsmodule = array(
                'name'     => 'M.theme.rlmaster.listen_color_collapse',
                'fullpath' => '/theme/'.$this->theme.'/javascript/colorpicker.js',
                'requires' => array('node', 'anim', 'transition')
            );
            $PAGE->requires->js_init_call('M.theme.rlmaster.listen_color_collapse.init', null, true, $colorsmodule);

            // Color div
            $html[] = '<div class="color_settings">';

            $settings = $this->get_setting();
            $defaults = $this->get_defaultsetting();

            $params = array('type'=>'text', 'size'=>'12');

            $index = 0;
            foreach (self::$sections as $k=>$v) {
                // Grouping header
                if ($index == 0) {
                    // Color grouping
                    $html[] = '<h3 class="expanded" role="tab" aria-selected="true">'.get_string($k, $this->plugin).'</h3>';
                } else {
                    $html[] = '<h3 class="collapsed" role="tab" aria-selected="false">'.get_string($k, $this->plugin).'</h3>';
                }
                // Group container
                if ($index == 0) {
                    // Color grouping
                    $html[] = '<div class="color-group expanded" role="tabpanel" aria-expanded="true" aria-hidden="false">';
                } else {
                    $html[] = '<div class="color-group collapsed" role="tabpanel" aria-expanded="false" aria-hidden="true" style="display:none;">';
                }
                $index++;
                foreach ($v as $value) {
                    $label = $value.'_label';
                    $description = $value.'_desc';
                    $id = $this->get_id().$value;
                    $name = $this->get_full_name().'['.$value.']';
                    $html[] = '<div class="form-label"><label>'.get_string($label, 'theme_rlmaster').'</label>';
                    $html[] = '<span class="form-shortname">theme_rlmaster | '.$value.'</span></div>';
                    $html[] = '<div class="form-setting">';
                    $html[] = '<div class="form-colourpicker defaultsnext">';
                    $html[] = '<div class="admin_colourpicker clearfix">';
                    $html[] = '<img alt="" class="colourdialogue" src="'.$CFG->wwwroot.'/theme/image.php?theme=rlmaster&amp;component=core&amp;rev=-1&amp;image=i/colourpicker">';
                    $html[] = '<div class="previewcolour" style="width: 50px; height: 50px; background-color:'.$settings[$value].'"></div>';
                    $html[] = '<div class="currentcolour" style="width: 50px; height: 49px;"></div></div>';
                    $html[] = '<input type="text" id="'.$id.'" name="'.$name.'" value="'.$settings[$value].'" size="12"></div>';
                    $html[] = '<div class="form-defaultinfo">'.get_string('defaultsettinginfo', 'admin', $defaults[$value]).'</div></div>';
                    $html[] = '<div class="form-description"><p>'.get_string($description, 'theme_rlmaster').'</p></div>';

                    $PAGE->requires->js_init_call('M.util.init_colour_picker', array($id, null));
                }
                $html[] = '</div>';
            }

            $html[] = '</div>';

            return implode($html, "\n");
        }

        /**
         * Save color configuration to file
         *
         * @return bool Success/Fail
         */
        public function save_to_file() {

            if (!($fp = @fopen($this->filename, 'w'))) {
                print_error('savefailed', $this->plugin, $this->filename);
            }

            fwrite($fp, "field, color\r\n");

            foreach ($this->colors as $field => $color) {
                fwrite($fp, "$field, $color\r\n");
            }
            fclose($fp);

            return true;
        }

        /**
         * Load color configuration from file
         *
         * @return bool Success/Fail
         */
        public function load_from_file() {

            if (!($handle = @fopen($this->filename, 'r'))) {
                print_error('loadfailed', $this->plugin, $this->filename);
            }

            $fieldnames = fgetcsv($handle, 4096);
            $field_exists = (array_key_exists(0, $fieldnames) && (trim(strtolower($fieldnames[0])) == 'field'));
            $color_exists = (array_key_exists(1, $fieldnames) && (trim(strtolower($fieldnames[1])) == 'color'));

            if (empty($fieldnames) || !$field_exists || !$color_exists) {
                fclose($handle);
                return false;
            }

            while (($data = fgetcsv($handle, 4096)) !== false) {
                $this->colors[$data[0]] = $data[1];
            }
            fclose($fp);

            return true;
        }

        /**
         * Validate data before storage
         *
         * @param array $data The data to be validated
         * @return mixed true if ok string if error found
         */
        public function validate($data) {
            // allow paramtype to be a custom regex if it is the form of /pattern/
            if (!is_array($data)) {
                return get_string('validateerror', 'admin');
            }

            foreach ($data as $key => $value) {

                if (preg_match('/^#?([a-fA-F0-9]{3}){1,2}$/', $value)) {

                    if (strpos($value, '#')!==0) {
                        $data[$key] = '#'.$value;
                    }

                } else if (preg_match('/^[a-zA-Z]{3,25}$/', $value)) {
                    // Ok

                } else if (empty($value)) {
                    $data[$key] = $this->colors[$key];

                } else {
                    return get_string('validationfailedcolor', $this->plugin, $key);
                }
            }
            return $data;
        }

        /**
         * Return the setting
         *
         * @return mixed returns config if successful else null
         */
        public function get_setting() {
            return $this->colors;
        }

        /**
         * Save the setting
         *
         * @param array $data The data to be written
         * @return string blank if ok, otherwise error message
         */
        public function write_setting($data) {

            // $data is an array
            $validated = $this->validate($data);
            if (!is_array($validated)) {
                return $validated;
            }

            foreach ($validated as $key => $value) {
                $this->colors[$key] = $value;
                if (!$this->config_write($key, $value)) {
                    return get_string('errorsetting', 'admin');
                }
            }
            if ($this->autosave) {
                $this->save_to_file();
            }
            return '';
        }
    }

    /**
     * There's no default filepicker object in Moodle 2.0, so we need to create one.
     *
     * @author  Tyler Bannister <tyler.bannister@remote-learner.net>
     * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
     */
    class rlmaster_admin_setting_filepicker extends admin_setting {

        // File System Variable
        protected $fs;

        // Contextid for file location
        protected $contextid;

        // Component for file location
        protected $component;

        // Item id for file location
        protected $itemid = SITEID;

        // File area for file location
        protected $filearea = 'files';

        // File path for file location
        protected $filepath = '/';

        // Plugin file url root - for handling image settings
        protected $pluginroot = '/pluginfile.php/';

        // File path for file location
        protected $repositorydir;

        // Theme name without the "theme_"
        protected $theme;

        /**
         * Config filepicker constructor
         *
         * @param string $name           Unique ascii name, either 'mysetting' for settings that in
         *                               config, or 'myplugin/mysetting' for ones in config_plugins.
         * @param string $visiblename    Localised
         * @param string $description    Long localised info
         * @param string $defaultsetting Default value
         * @uses $CFG;
         * @uses $PAGE;
         */
        public function __construct($name, $visiblename, $description, $defaultsetting) {
            global $CFG, $PAGE;

            parent::__construct($name, $visiblename, $description, $defaultsetting);

            $this->fs = get_file_storage();
            $this->contextid = SYSCONTEXTID;
            $this->component = $this->plugin;
            $this->repositorydir = $CFG->dataroot .'/repository/'. $this->component;
            $this->theme = substr($this->component, 6);

            rlmaster_admin_setting_controls::create_file_repository($this->contextid,
                    $this->component, $this->filearea, $this->itemid, $this->plugin);

            if (!$PAGE->requires->is_head_done()) {
                $PAGE->requires->css('/theme/'. $this->theme .'/style/filepicker.css');
            }
        }

        /**
         * Return the setting
         *
         * @return mixed returns config if successful else null
         */
        public function get_setting() {
            $setting = $this->config_read($this->name);
            // Can't return null or we get stuck on the upgrade page.
            if ($setting === null) {
                $setting = '';
            }
            return $setting;
        }

        /**
         * Save the setting
         *
         * @param int $data The file id
         * @return string blank if ok, otherwise error message
         * @uses $CFG
         * @uses $USER
         */
        public function write_setting($data) {
            global $CFG, $USER;

            $this->create_file_storage();

            // $data is a integer
            $validated = $this->validate($data);

            if ($validated !== true) {
                return $validated;
            }

            $usercontext = context_user::instance($USER->id);
            $files = $this->fs->get_area_files($usercontext->id, 'user', 'draft', $data);

            $url = $this->config_read($this->name);
            $filearea = $this->name.'_'.$this->filearea;

            // If there's at least one file (because one is a directory)
            if (count($files)>=2) {
                $count = 0;
                // Set itemid to data
                $itemid = $data;

                $file_record = array(
                    'contextid' => $this->contextid,
                    'component' => $this->component,
                    'filearea'  => $filearea,
                    'itemid'    => $itemid,
                    'filepath'  => $this->filepath
                );

                foreach ($files as $draftfile) {
                    // There's always a directory entry.
                    if (!$draftfile->is_directory()) {
                        $file_record['filename'] = $draftfile->get_filename();

                        $exists = false;
                        $file = $this->fs->get_file($this->contextid, $this->component, $filearea, $itemid, $this->filepath, $file_record['filename']);

                        // If there's a file with the same name...
                        if ($file) {
                            $exists = true;
                            $samesize = ($file->get_filesize() == $draftfile->get_filesize());
                            $sametime = ($file->get_timemodified() == $draftfile->get_timemodified());

                            // Check if it's the same file.  If it's not, delete it.
                            if ((!$samesize || !$sametime) && $file->delete()) {
                                $exists = false;
                            }
                        }

                        // We don't delete the old file because it could be used elsewhere in the theme
                        if (!$exists) {
                            $this->fs->create_file_from_storedfile($file_record, $draftfile);
                            $destination = $this->repositorydir . $file_record['filepath'] . $file_record['filename'];
                            $draftfile->copy_content_to($destination);
                            touch($destination, $draftfile->get_timemodified());
                        }

                        $url = $this->pluginroot.$this->contextid.'/'.$this->component.'/'.$filearea.'/'.$itemid.$this->filepath.$file_record['filename'];

                        if ($count > 0) {
                            break;
                        } else {
                            $count++;
                        }
                    }
                }
                // Clear out previous theme files for this element
                $this->fs->delete_area_files($this->contextid, $this->component, $filearea);

                // Use the draft area
                $elname = $this->get_full_name();
                $draftitemid = file_get_submitted_draft_itemid($elname);
                file_save_draft_area_files($draftitemid, $this->contextid, $this->component, $filearea, $itemid);
            } else {
                // Clean out the url
                $url = '';
            }

            return ($this->config_write($this->name, $url) ? '' : get_string('errorsetting', 'admin'));
        }

        /**
         * Create the file storage area if it doesn't already exist
         *
         * @return bool Success/failure
         */
        public function create_file_storage() {
            $filearea = $this->name.'_'.$this->filearea;
            $pathhash = $this->fs->get_pathname_hash($this->contextid, $this->component, $filearea, $this->itemid, $this->filepath, '.');

            if (!($dir_info = $this->fs->get_file_by_hash($pathhash))) {
                $this->fs->create_directory($this->contextid, $this->component, $filearea, $this->itemid, $this->filepath);
            }
        }

        /**
         * Validate data before storage
         *
         * @param string $data The data to be validated
         * @return mixed true if ok string if error found
         */
        public function validate($data) {
            // allow paramtype to be a custom regex if it is the form of /pattern/
            $cleaned = clean_param($data, PARAM_INT);
            if ("$data" === "$cleaned") { // implicit conversion to string is needed to do exact comparison
                return true;
            } else {
                return get_string('validateerror', 'admin');
            }
        }

        /**
         * Return an XHTML string for the setting
         *
         * @param mixed  $data  Array or string depending on setting
         * @param string $query Query
         * @return string Returns an XHTML string
         * @uses $CFG
         * @uses $OUTPUT
         * @uses $PAGE
         */
        public function output_html($data, $query='') {
            global $CFG, $OUTPUT, $PAGE;

            // For the filemanager
            require_once("$CFG->dirroot/repository/lib.php");
            require_once("$CFG->libdir/form/filemanager.php");

            $default = $this->get_defaultsetting();

            $options = new stdClass();
            $options->maxbytes       = get_max_upload_file_size();
            $options->maxfiles       = 1;
            $options->accepted_types = array('.jpe', '.jpeg', '.jpg', '.png', '.gif');
            $options->return_types   = FILE_INTERNAL;

            // Set filearea
            $filearea = $this->name.'_'.$this->filearea;

            $options->elementname = substr($this->get_id(), 3);

            $elname = $this->get_full_name();

            if (($data != '') && (strpos($data, $this->pluginroot) !== false)) {
                $pos = strlen($this->pluginroot) -1;  // Need starting slash
                $options->themefilepath = dirname(substr($data, $pos));
                // Get itemid from filepath
                $options->itemid = basename($options->themefilepath);
            } else {
                $options->itemid = file_get_unused_draft_itemid();
                // Build filepath from SYSCONTEXTID, theme path, and itemid
                $options->themefilepath = $this->contextid.'/theme/'.$this->theme.'/'.$filearea.'/'.$options->itemid;
            }

            // Prepare draft area with existing file
            // Reset draftitemid to 0 - this way a new filearea for this user is created
            $draftitemid = 0;
            file_prepare_draft_area($draftitemid, $this->contextid, $this->component, $filearea, $options->itemid);

            // Reset options itemid to new draftitemid generated from file_prepare_draft_area
            $options->itemid = $draftitemid;

            // Generate new file manager
            $fm = new form_filemanager($options);
            $output = $PAGE->get_renderer('core', 'files');
            $html = $this->description.$output->render($fm);

            // Add hidden itemid for write_setting
            $html .= '<input type="hidden" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.$options->itemid.'" />';

            $warning = $this->file_warning($options->itemid);

            return format_admin_setting($this, $this->visiblename, $html, $warning, true, '', $default, $query);
        }


        /**
         * Issue a warning for files greater than the specified size.
         *
         * @param int $itemid Item ID
         * @return string Warning message
         */
        public function file_warning($itemid) {
            global $USER, $OUTPUT;

            $warning = '';
            $usercontext = context_user::instance($USER->id);
            $files = $this->fs->get_area_files($usercontext->id, 'user', 'draft', $itemid);

            foreach ($files as $file) {
                // Issue warning for files greater than 500KB.
                if ($file->get_filesize() > THEME_RLMASTER_MAX_FILE_SIZE) {
                    $msg = get_string('filewarning', $this->plugin);
                    // Risk_xss image used to show exclamation mark icon.
                    $warning = html_writer::empty_tag('img', array('alt' => $msg, 'src' => $OUTPUT->pix_url('i/risk_xss')));
                    $warning .= ' '.$msg;
                }
            }

            return $warning;
         }
    }

    /**
     * This object allows files to be uploaded and is to be used in conjunction with the file picker.
     *
     * @author  Tyler Bannister <tyler.bannister@remote-learner.net>
     * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
     */
    class rlmaster_admin_setting_fileupload extends admin_setting {
        protected $theme = 'theme';

        // Don't show save changes - controls needs this
        public $nosave = true;

        /**
         * Config fileupload constructor
         *
         * @param string $name           Unique ascii name, either 'mysetting' for settings that in
         *                               config, or 'myplugin/mysetting' for ones in config_plugins.
         * @param string $visiblename    Localised
         * @param string $description    Long localised info
         * @param string $defaultsetting Default value
         */
        public function __construct($name, $visiblename, $description, $defaultsetting=null) {
            global $PAGE;

            parent::__construct($name, $visiblename, $description, $defaultsetting);

            $this->theme = substr($this->plugin, 6);

            $contextid = $PAGE->context->id;
            $component = $this->plugin;
            $itemid    = SITEID;
            $filearea  = $this->name.'_'.'files';

            rlmaster_admin_setting_controls::create_file_repository($contextid, $component, $filearea, $itemid, $this->plugin);

        }

        /**
         * Return the setting
         *
         * @return mixed returns config if successful else null
         */
        public function get_setting() {
            return '';
        }

        /**
         * Save the setting
         *
         * @param string $data The data to be written
         * @return string blank if ok, otherwise error message
         */
        public function write_setting($data) {

            // $data is a string
            $validated = $this->validate($data);

            if ($validated !== true) {
                return $validated;
            }
            return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
        }

        /**
         * Validate data before storage
         *
         * @param string $data The data to be validated
         * @return mixed true if ok string if error found
         */
        public function validate($data) {
            // allow paramtype to be a custom regex if it is the form of /pattern/
            $cleaned = clean_param($data, PARAM_FILE);

            if ("$data" === "$cleaned") { // implicit conversion to string is needed to do exact comparison
                return true;
            } else {
                return get_string('validateerror', 'admin');
            }
        }

        /**
         * Return an XHTML string for the setting
         *
         * @param mixed  $data  Array or string depending on setting
         * @param string $query Query
         * @return string Returns an XHTML string
         * @uses $CFG
         * @uses $OUTPUT
         * @uses $PAGE
         */
        public function output_html($data, $query='') {
            global $CFG, $OUTPUT, $PAGE;

            $uploadpage = $CFG->wwwroot .'/theme/'. $this->theme .'/upload.php';
            $uploadtext = get_string('uploadlink', $this->plugin);
            $pop        = new popup_action('click', $uploadpage);
            $link       = $OUTPUT->action_link($uploadpage, $uploadtext, $pop);

            return get_string('uploadtext', $this->plugin, $link);
        }
    }

    /**
     * This object causes files and color data to be loaded from the theme repository
     *
     * @author  Tyler Bannister <tyler.bannister@remote-learner.net>
     * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
     */
    class rlmaster_admin_setting_controls extends admin_setting {

        // List of images
        public static $images = array(
                'background', 'banner', 'blockheadback', 'custommenuback', 'headerback',
                'headerleft', 'headerright', 'footerback', 'headermenuback', 'headingback', 'favicon'
        );

        // Component for file location
        protected $component;

        // Configuration file name
        protected $configfilename = 'config.csv';

        // Configuration file path
        protected $configpath;

        // Contextid for file location
        protected $contextid;

        // File area for file location
        protected $filearea = 'files';

        // File path for file location
        protected $filepath = '/';

        // Filesystem holder variable
        protected $fs;

        // Item id for file location
        protected $itemid = SITEID;

        // Plugin file url root - for handling image settings
        protected $pluginroot = '/pluginfile.php/';

        // Repository root directory - for handling uploads and downloads
        protected $reporoot;

        // Theme name
        protected $theme;

        // Zip file name
        protected $zipfilename = 'config.zip';

        // Don't show save changes
        public $nosave = true;


        /**
         * Config controls constructor
         *
         * @param string $name        Unique ascii name, either 'mysetting' for settings that in
         *                            config, or 'myplugin/mysetting' for ones in config_plugins.
         * @param string $visiblename Localised
         * @param string $description Long localised info
         * @uses $CFG
         * @uses $PAGE
         */
        public function __construct($name, $visiblename, $description) {
            global $CFG, $COURSE, $PAGE;

            parent::__construct($name, $visiblename, $description, '');

            $this->fs         = get_file_storage();
            $this->component  = $this->plugin;
            $this->reporoot   = $CFG->dataroot .'/repository/'. $this->component;
            $this->contextid  = SYSCONTEXTID;
            $this->configpath = $this->reporoot .'/'. $this->configfilename;
            $this->theme      = substr($this->component, 6);

            $shortname = (isset($COURSE->shortname) && is_string($COURSE->shortname))
                    ? preg_replace('/[^a-zA-Z0-9]/','_', $COURSE->shortname)
                    : 'site';
            $date      = date('Ymd');
            $this->zipfilename    = $shortname .'_'. $this->plugin .'-'. $date .'.zip';

            self::create_file_repository($this->contextid, $this->component, $this->filearea,
                                         $this->itemid, $this->plugin);

            if (!$PAGE->requires->is_head_done()) {
                $PAGE->requires->css('/theme/'. $this->theme .'/style/filepicker.css');
                $PAGE->requires->js('/theme/'. $this->theme .'/javascript/controls.js');
            }

        }

        /**
         * Create the file repository if it doesn't already exist
         *
         * @param int    $contextid The id of the $context for the repository
         * @param string $component The component name
         * @param string $filearea  The file area name
         * @param int    $itemid    The id of the item to save
         * @param string $plugin    The name of the plugin
         * @return bool Success/failure
         */
        public static function create_file_repository($contextid, $component, $filearea, $itemid, $plugin) {
            global $CFG;

            $exists        = false;
            $type          = 'filesystem';
            $context       = context_system::instance();
            $repositorydir = $CFG->dataroot .'/repository/'. $component;
            $fs            = get_file_storage();


            $repositories = repository::get_instances(array('type' => $type));

            foreach ($repositories as $repository) {

                if (array_key_exists('fs_path', $repository->options) && ($repository->options['fs_path'] == $component)) {
                    $exists = true;
                }
            }

            if (!file_exists($repositorydir)) {
                mkdir($repositorydir, 0755, true);
                $files = $fs->get_area_files($contextid, $component, $filearea, $itemid);

                if (count($files)>=2) {
                    $count = 0;

                    foreach ($files as $file) {

                        if (!$file->is_directory()) {
                            $name = $file->get_filename();
                            $path = $file->get_filepath();
                            $destination = $repositorydir . $path . $name;
                            $file->copy_content_to($destination);
                            touch($destination, $file->get_timemodified());
                        }
                    }
                }

            } else if (!is_dir($repositorydir)) {
                print_error('repositorybroken', $plugin);
            }

            if (!$exists) {
                // If there are no filesystem repositories, assume they haven't been configured.
                if (sizeof($repositories) == 0) {
                    $repoplugin = new repository_type($type, array(), true);
                    // Create might fail because there doesn't appear to be a way to test if the type
                    // already exists.  So we make it silent to avoid errors.
                    $repoplugin->create(true);
                }

                $params = array('name'    => get_string('pluginname', $plugin),
                                'fs_path' => $component);
                repository::create($type, 0, $context, $params, 0);
            }
        }

        /**
         * Always returns true
         *
         * @return bool Always returns true
         */
        public function get_setting() {
            return true;
        }

        /**
         * Always returns true
         *
         * @return bool Always returns true
         */
        public function get_defaultsetting() {
            return true;
        }

        /**
         * Save configuration to file
         *
         * @param string $filename The name of the file to save configuration to
         * @return bool Success/Fail
         */
        public function save_config($filename) {
            $config     = get_config($this->plugin);
            $array      = (array) $config;

            if (!($fp = @fopen($filename, 'w'))) {
                return get_string('savefailed', $this->plugin, $filename);
            }

            fwrite($fp, "\"field\",\"value\"\r\n");

            foreach ($array as $field => $value) {

                if (!strpos($value, "\n")) {
                    $esc_value = str_replace('"', '""', $value);
                    fwrite($fp, "\"$field\",\"$esc_value\"\r\n");
                } else {
                    $lines = explode("\n", $value);

                    foreach ($lines as $line) {
                        $esc_line = str_replace('"', '""', $line);
                        fwrite($fp, "\"$field\",\"".rtrim($esc_line)."\"\r\n");
                    }
                }
            }
            fclose($fp);

            return true;
        }

        /**
         * Load images into internal file cache
         * @param array  $files    A list of files and corresponding itemids used in the theme
         *
         * @return bool Success/Fail
         */
        public function load_images($files) {
            global $CFG, $USER;

            // Remove all images stored for this theme
            $this->fs->delete_area_files(SYSCONTEXTID, 'theme_rlmaster');

            $pos    = strlen($this->pluginroot) -1;  // Need starting slash
            $errors = array();

            foreach (self::$images as $image) {
                $url = get_config($this->plugin, $image);
                if (strpos($url, $this->pluginroot) !== false) {
                    $path     = substr($url, $pos);
                    $filename = basename($url);
                    $repopath = $this->reporoot . $this->filepath . $filename;

                    // Check if file exists in the file repository
                    if (!file_exists($repopath)) {
                        $errors[] = get_string('missingfile', $this->plugin, $filename);
                        continue;
                    }

                    if (isset($files[$filename])) {
                        $itemid = $files[$filename]['itemid'];
                        $filearea = $files[$filename]['form_element'].'_'.$this->filearea;
                    } else {
                        $itemid = file_get_unused_draft_itemid();
                        $filearea = $this->name.'_'.$this->filearea;
                    }

                    $source = $filename;
                    $author = fullname($USER);
                    $userid = $USER->id;
                    if (isset($CFG->sitedefaultlicense)) {
                        $license = $CFG->sitedefaultlicense;
                    } else {
                        $license = null;
                    }

                    // Each file needs to be treated as if it was added via the file manager,
                    // thus rendering it editable in the images tab

                    // Create draft area file first
                    $usercontext    = context_user::instance($USER->id);
                    $draftfileinfo = array(
                        'contextid' => $usercontext->id,
                        'component' => 'user',
                        'filearea'  => 'draft',
                        'itemid'    => $itemid,
                        'filepath'  => $this->filepath,
                        'filename'  => $filename,
                        'source'    => $source,
                        'author'    => $author,
                        'userid'    => $userid,
                        'license'   => $license
                    );

                    $path = $this->fs->get_pathname_hash($usercontext->id, 'user', 'draft', $itemid, $this->filepath, $filename);
                    $file = $this->fs->get_file_by_hash($path);
                    if ($file) {
                        // Prevent SQL duplication errors from create_file_from_pathname by removing images that already exist with the same hash.
                        $file->delete();
                    }

                    // Save draft file to database
                    $this->fs->create_file_from_pathname($draftfileinfo, $repopath);

                    // Create theme file to be saved in database
                    $fileinfo = array(
                        'contextid' => $this->contextid,
                        'component' => $this->component,
                        'filearea'  => $filearea,
                        'itemid'    => $itemid,
                        'filepath'  => $this->filepath,
                        'filename'  => $filename,
                        'source'    => $source,
                        'author'    => $author,
                        'userid'    => $userid,
                        'license'   => $license
                    );

                    // filepath s.b. filearea / itemid / filename
                    $path = $this->filearea.'/'.$itemid.'/'.$filename;

                    // check if the file exists in the file cache
                    if ($file = $this->fs->get_file_by_hash(sha1($path))) {
                        $file->delete();
                    }

                    // Clear out previous theme files for this element
                    $this->fs->delete_area_files($this->contextid, $this->component, $filearea);

                    // Save file to database
                    $this->fs->create_file_from_pathname($fileinfo, $repopath);
                }
            }

            return implode("\n", $errors);
        }

        /**
         * Load configuration from file
         *
         * @param string $filename The name of the configuration file to load
         * @param array  $files    A list of files and corresponding itemids used in the theme
         * @return bool Success/Fail
         */
        public function load_config($filename, &$files) {

            if (!($handle = @fopen($filename, 'r'))) {
                return get_string('loadfailed', $this->plugin, $filename);
            }

            $fieldnames = fgetcsv($handle, 4096);
            $field_exists = (array_key_exists(0, $fieldnames) && (trim(strtolower($fieldnames[0])) == 'field'));
            $value_exists = (array_key_exists(1, $fieldnames) && (trim(strtolower($fieldnames[1])) == 'value'));

            if (empty($fieldnames) || !$field_exists || !$value_exists) {
                fclose($handle);
                return get_string('invalidconfigurationformat');
            }

            $field = '';
            $value = '';

            while (($data = fgetcsv($handle, 4096)) !== false) {

                if (trim(strtolower($data[0])) == 'version') {
                    // TODO: Implement upgrade logic based on version?
                    continue;
                }

                // Check if this config setting continues across multiple lines
                if ($field != $data[0]) {

                    // If the setting isn't blank
                    if ($field != '') {
                        // We need to rewrite file configs so they reference our files.
                        if (preg_match('|^'. $this->pluginroot .'|', $value)) {
                            $filepath = substr($value, strpos($value, '/', 18) + 1);
                            // filepath s.b. filearea / itemid / filename
                            $filename = basename($filepath);
                            if (isset($files[$filename])) {
                                $itemid = $files[$filename]['itemid'];
                                $files[$filename]['form_element'] = $field;
                            } else {
                                $itemid = file_get_unused_draft_itemid();
                                $files[$filename]['itemid'] = $itemid;
                                $files[$filename]['form_element'] = $field;
                            }
                            $filearea = $field.'_'.$this->filearea;
                            $path = $filearea.'/'.$itemid.'/'.$filename;
                            $value = $this->pluginroot.$this->contextid.'/'.$this->component.'/'.$path;
                        }
                        set_config($field, $value, $this->plugin);
                    }
                    $field = trim($data[0]);
                    $value = trim($data[1]);
                } else {
                    $value .= "\n". $data[1];
                }
            }

            // Set the final config setting, if it's not blank
            if ($field != '') {
                set_config($field, $value, $this->plugin);
            }

            fclose($handle);

            return '';
        }

        /**
         * Reset settings to theme defaults.
         *
         * @return string Always returns an empty string
         */
        public function reset() {
            global $CFG, $USER;

            $defaults = rlmaster_create_defaults();

            // Reset config plugin fields to defaults
            foreach ($defaults as $field => $value) {
                set_config($field, $value, $this->plugin);
            }

            // Update defaults with the proper path to default images
            $defaults = rlmaster_load_default_images($this->plugin, $defaults);

            // Reset config plugin fields to defaults
            foreach ($defaults as $field => $value) {
                set_config($field, $value, $this->plugin);
            }

            if ($CFG->theme == $this->theme) {
                rlmaster_reset_theme_cache($CFG->theme);
            }

            return '';
        }

        /**
         * Import settings from a file upload
         *
         * @param int $picker The id of the filepicker to use
         * @return string Blank string or error message
         * @uses $USER
         */
        public function import($picker) {
            global $CFG, $USER;

            $imported_files = array();
            $usercontext = context_user::instance($USER->id);
            $files = $this->fs->get_area_files($usercontext->id, 'user', 'draft', $picker);

            if (count($files)>=2) {
                $count = 0;

                foreach ($files as $file) {

                    // If it's not a directory, it should be the archive.
                    if (!$file->is_directory()) {
                        $zipper = new zip_packer();
                        $processed = $zipper->extract_to_pathname($file, $this->reporoot);
                    }
                }

                // Generate a unique itemid for each file in the zip
                foreach ($processed as $file=>$value) {
                    $imported_files[$file]['itemid'] = file_get_unused_draft_itemid();
                }
            }

            $this->fs->delete_area_files($usercontext->id, 'user', 'draft', $picker);
            $result = $this->load_config($this->configpath, $imported_files);

            if ($result === '') {
                $result = $this->load_images($imported_files);
            }

            if ($CFG->theme == $this->theme) {
                rlmaster_reset_theme_cache($CFG->theme);
            }

            return $result;
        }

        /**
         * Export settings from the file repository.
         *
         * @return string Blank string or error message
         * @uses $USER
         */
        public function export() {
            global $USER;

            $configpath = $this->reporoot .'/'. $this->configfilename;
            $this->save_config($configpath);

            // user context
            $user_context = context_user::instance($USER->id);

            $files    = $this->fs->get_area_files($this->contextid, $this->component, $this->filearea);
            $zipfiles = array('/' => $this->reporoot);

            // Format the files with 'relative path' => file for proper display in zip.
            foreach ($files as $file) {

                if ($file->get_filename() != '.') {
                    $zipfiles[$file->get_filename()] = $file;
                }
            }

            $zipper = new zip_packer();
            $newfile = $zipper->archive_to_storage($zipfiles, $user_context->id, 'user', 'draft',
                                                   $this->itemid, '/', $this->zipfilename, $USER->id);
            if ($newfile) {
                $fileurl = moodle_url::make_draftfile_url($this->itemid, '/', $this->zipfilename)->out();
                header('Location: ' . $fileurl );
            } else {
                return get_string('cannotcreatezip', $this->plugin);
            }

            return '';
        }

        /**
         * Write settings.
         *
         * In practice this actually runs the reset, import or export sub actions.
         *
         * @param array $data The submitted data to act upon.
         * @return string Always returns an empty string
         */
        public function write_setting($data) {
            $result = '';

            if (isset($data['action'])) {

                if ($data['action'] == 1) {
                    $result = $this->reset();

                } else if ($data['action'] == 2) {
                    $result = $this->import($data['picker']);

                } else if ($data['action'] == 3) {
                    $result = $this->export();
                }
            }
            return $result;
        }

        /**
         * Returns an HTML string
         *
         * @param mixed  $data  Array or string depending on setting
         * @param string $query Query
         * @return string Returns an HTML string
         * @uses $PAGE
         * @uses $OUTPUT
         */
        public function output_html($data, $query='') {
            global $CFG, $PAGE, $OUTPUT;

            // For the filemanager
            require_once("$CFG->dirroot/repository/lib.php");
            require_once("$CFG->libdir/form/filemanager.php");

            $theme   = substr($this->component, strpos($this->component, '_')+1);

            $options = new stdClass();
            $options->maxbytes       = get_max_upload_file_size();
            $options->maxfiles       = 1;
            // Using the group name of archive is not working, so listing a selection of the each mime type
            // within the archive group found in get_mimetypes_array in lib/filelib.php
            $options->accepted_types = array('.gtar', '.gz', '.gzip', '.hqx', '.sit', '.tar', '.tgz', '.zip');
            $options->return_types   = FILE_INTERNAL;
            $options->filepath       = "/theme/$theme/";
            $options->itemid         = file_get_unused_draft_itemid();

            // Set filearea
            $filearea = $this->name.'_'.$this->filearea;

            // Generate new file manager
            $fp = new form_filemanager($options);
            $output = $PAGE->get_renderer('core', 'files');

            $html[] = '<input type="hidden" id="'.$this->get_id().'" name="'.$this->get_full_name().'[action]" value="0" />';
            $html[] = '<input type="hidden" id="'.$this->get_id().'_picker" name="'.$this->get_full_name().'[picker]" value="'.$options->itemid.'" />';
            $html[] = $this->description;

            $html[] = $output->render($fp);

            $html[] = '<input type="button" value="'.get_string('reset', $this->plugin).'" onclick="M.core_formchangechecker.set_form_submitted();'.
                      'return rlmaster_change_field(\''.$this->get_id().'\', 1);" />';
            $html[] = '<input type="submit" value="'.get_string('import', $this->plugin).'" onclick="M.core_formchangechecker.set_form_submitted();'.
                      'return rlmaster_change_field(\''.$this->get_id().'\', 2);" />';
            $html[] = '<input type="submit" value="'.get_string('export', $this->plugin).'" onclick="M.core_formchangechecker.set_form_submitted();'.
                      'return rlmaster_change_field(\''.$this->get_id().'\', 3);" />';

            return format_admin_setting($this, $this->visiblename, implode($html, "\n"), '', true, '', null, $query);
        }
    }
    /**
     * This object is for implementing tabs on an admin setting page.
     *
     * @author  Tyler Bannister <tyler.bannister@remote-learner.net>
     * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
     */
    class rlmaster_admin_setting_tabs extends admin_setting {

        protected $tabs     = array(0 => array());
        protected $selected;
        protected $section;
        protected $reload;

        /**
         * Config fileupload constructor
         *
         * @param string  $name    Unique ascii name, either 'mysetting' for settings that in
         *                         config, or 'myplugin/mysetting' for ones in config_plugins.
         * @param string  $section Section name
         * @param boolean $reload  Whether to reload
         */
        public function __construct($name, $section, $reload) {
            parent::__construct($name, '', '', '');

            global $PAGE;

            $this->section = $section;
            $this->reload  = $reload;
            $this->component  = $this->plugin;
            $this->theme      = substr($this->component, 6);

            // Check for direct links
            $this->selected = optional_param($this->get_full_name(), 0, PARAM_INT);

            if ($this->reload) {
                $newtab = optional_param($this->get_full_name() .'_new', -1, PARAM_INT);

                if ($newtab != -1) {
                    $this->selected = $newtab;
                }
            }

            if (!$PAGE->requires->is_head_done()) {
                $PAGE->requires->css('/theme/'.$this->theme.'/style/filepicker.css');
                $PAGE->requires->js('/theme/'.$this->theme.'/javascript/controls.js');
            }

        }

        /**
         * Return the currently selected tab.
         *
         * @return int The id of the currently selected tab.
         */
        public function get_setting() {
            return $this->selected;
        }

        /**
         * Always returns true
         *
         * @return bool Always returns true
         */
        public function get_defaultsetting() {
            return true;
        }

        /**
         * Don't write the setting, just set the currently selected tab
         *
         * To handle automatic tab saving we need 2 values, the old tab and the new tab.
         * We also need to handle the direct link therefore we use an optional param to find
         * out if we are supposed to be loading a new page.  However, the values of the old page
         * must be saved, therefore page changes must occur a the reload stage only.
         *
         * @param int $data The current selected tab id
         * @return string Always returns an empty string
         */
        public function write_setting($data) {
            $this->selected = intval($data);

            // do not write any setting
            return '';
        }

        /**
         * Add a tab to the tab row
         *
         * For now we only implement a single row.  Multiple rows could be added as an extension
         * later.
         *
         * @param int    $id   The tab id
         * @param string $name The tab name
         * @uses $CFG
         */
        function addtab($id, $name) {
            global $CFG;

            $url = $CFG->wwwroot .'/admin/settings.php?section='. $this->section .'&amp;'
                 .$this->get_full_name().'='.$id.'" class="rlmaster-admin-tab';

            $tab = new tabobject($id, $url, $name);

            $this->tabs[0][] = $tab;
        }

        /**
         * Returns an HTML string
         *
         * @param mixed  $data  Array or string depending on setting
         * @param string $query Query
         * @return string Returns an HTML string
         */
        public function output_html($data, $query='') {

            global $CFG, $PAGE;

            $this->component = $this->plugin;
            $this->theme     = substr($this->component, 6);
            $tabsmodule = array(
                'name'     => 'M.theme.rlmaster.manage_tabs',
                'fullpath' => '/theme/'.$this->theme.'/javascript/controls.js',
                'requires' => array('node')
            );
            $PAGE->requires->js_init_call('M.theme.rlmaster.manage_tabs.init', null, true, $tabsmodule);

            $output  = print_tabs($this->tabs, $this->selected, null, null, true);

            $properties = array(
                    'type'  => 'hidden',
                    'name'  => $this->get_full_name(),
                    'value' => $this->get_setting()
            );

            // Set this flag for the controls tab
            if ($this->selected == THEME_RLMASTER_TAB_CONTROLS) {
                $this->nosave = true;
            }

            $output .= html_writer::empty_tag('input', $properties);

            $properties['id']   = $this->get_id();
            $properties['name'] = $this->get_full_name() .'_new';

            $output .= html_writer::empty_tag('input', $properties);

            return $output;
        }
    }

    /**
     * This setting has no interface, just clears the themecache when saved. Add it to any settings page where
     * you'd like the theme cache cleared when the page's settings are saved.
     *
     * @author  Tyler Bannister <tyler.bannister@remote-learner.net>
     * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
     */
    class rlmaster_admin_setting_clearthemecache extends admin_setting {

        /**
         * Config controls constructor
         *
         * @param string $name        Unique ascii name, either 'mysetting' for settings that in
         *                            config, or 'myplugin/mysetting' for ones in config_plugins.
         * @param string $visiblename Localised
         * @param string $description Long localised info
         * @uses $CFG
         * @uses $PAGE
         */
        public function __construct($name, $visiblename, $description) {
            global $CFG, $COURSE, $PAGE;
            parent::__construct($name, $visiblename, $description, '');
            $this->component  = $this->plugin;
            $this->theme      = substr($this->component, 6);
        }

        /**
        * Returns current value of this setting
        * @return mixed array or string depending on instance, NULL means not set yet
        */
        public function get_setting() {
            return '';
        }

        /**
         * Always returns true
         *
         * @return bool Always returns true
         */
        public function get_defaultsetting() {
            return true;
        }

        /**
        * Just a hidden input with a unique value to prompt admin settings to run write_setting on submit
        * @return string Returns an XHTML string
        */
        public function output_html($data, $query='') {
            return '<input type="hidden" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.uniqid('',true).'" />';
        }

        /**
        * Don't store anything, just reset the cache.
        *
        * @param mixed $data string or array, must not be NULL
        * @return string empty string if ok, string error message otherwise
        */
        public function write_setting($data) {
            global $CFG;
            if ($CFG->theme == $this->theme) {
                rlmaster_reset_theme_cache($this->theme);
            }

            // do not write any setting
            return '';
        }
    }

    /** This class sets up a file picker that only allows favourite icon file types
     */
    class rlmaster_admin_setting_faviconpicker extends rlmaster_admin_setting_filepicker {
        /**
         * Return an XHTML string for the setting
         *
         * @param mixed  $data  Array or string depending on setting
         * @param string $query Query
         * @return string Returns an XHTML string
         * @uses $CFG
         * @uses $OUTPUT
         * @uses $PAGE
         */
        public function output_html($data, $query='') {
            global $CFG, $OUTPUT, $PAGE, $USER;

            $default = $this->get_defaultsetting();
            $file    = null;

            $options = new stdClass();
            $options->maxbytes       = get_max_upload_file_size();
            $options->accepted_types = array('.ico');
            $options->maxfiles       = 1;
            $options->return_types   = FILE_INTERNAL;

            // Set filearea
            $filearea = $this->name.'_'.$this->filearea;

            $options->elementname = substr($this->get_id(), 3);

            $elname = $this->get_full_name();

            if (($data != '') && (strpos($data, $this->pluginroot) !== false)) {
                $pos = strlen($this->pluginroot) -1;  // Need starting slash
                $options->themefilepath = dirname(substr($data, $pos));
                $options->currentfile = substr($data, $pos);
                // Get itemid from filepath
                $options->itemid = basename($options->themefilepath);
            } else {
                // No existing files so...
                // Get the itemid beforehand so it can be passed to write_setting
                $options->itemid = file_get_unused_draft_itemid();

                // Build filepath from SYSCONTEXTID, theme path, and itemid
                $options->themefilepath = $this->contextid.'/theme/'.$this->theme.'/'.$filearea.'/'.$options->itemid;
            }

            // Prepare draft area with existing file
            // Reset draftitemid to 0 - this way a new filearea for this user is created
            $draftitemid = 0;
            file_prepare_draft_area($draftitemid, $this->contextid, $this->component, $filearea, $options->itemid);

            // Reset options itemid to new draftitemid generated from file_prepare_draft_area
            $options->itemid = $draftitemid;

            // Generate new file manager
            $fm = new form_filemanager($options);
            $output = $PAGE->get_renderer('core', 'files');
            $html = $this->description.$output->render($fm);

            // Add hidden itemid for write_setting
            $html.= '<input type="hidden" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.$options->itemid.'" />';

            $warning = $this->file_warning($options->itemid);

            return format_admin_setting($this, $this->visiblename, $html, $warning, true, '', $default, $query);
        }
    }
}
